package com.test.intent;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.TextView;
import android.widget.Toast;

/**
 * <pre>
 * Android 的一个特色就是 application A 的 activity 可以启动 application B 的 activity，尽管 A 和 B 是
 * 毫无干系的，而在用户看来，两个场景紧密联系，视觉上二者构成了一个整体。Android 就是把这种误觉定义为
 * Task，它既不是 class，也不是 AndroidMainifest.xml 中的一个元素。从表现上看 Task 就像是一个 stack，
 * 一个一个的 activity 是构成 stack 的元素，做着入栈 (push) 和出栈 (pop-up)这样简单重复性的劳动。
 * 
 * 默认的规则总是满足大多数的应用场景，但是也总会有一些例外打破习以为常的惯例。Task 的默认规则同样并非
 * 牢不可破，修改的方法还是有的。借助 Intent 中的 flag 和 AndroidMainifest.xml 中 activity 元素的属性，
 * 就可以控制到 Task 里 Activity 的关联关系和行为。
 * 
 * 在 android.content.Intent 中一共定义了20种不同的 flag，其中和 Task 紧密关联的有四种：
 * 1.FLAG_ACTIVITY_NEW_TASK
 * 2.FLAG_ACTIVITY_CLEAR_TOP
 * 3.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
 * 4.FLAG_ACTIVITY_SINGLE_TOP
 * 
 * 在使用这四个 flag 时，一个 Intent 可以设置一个 flag，也可以选择若干个进行组合。
 * 
 * 默认情况下，通过 startActivity() 启动一个新的 Activity，新的 Activity 将会和调用者在同一个 stack 
 * 中。但是，如果在传递给 startActivity() 的 Intent 对象里包含了 FLAG_ACTION_NEW_TASK，情况将发生变
 * 化，–系统将为新的 Activity “寻找”一个不同于调用者的 Task。不过要找的 Task 是不是一定就是 NEW 呢？如
 * 果是第一次执行，则这个设想成立，如果说不是，也就是说已经有一个包含此 Activity 的Task 存在，则不会
 * 再启动 Activity。
 * 
 * 如果 flag 是 FLAG_ACTIVITY_CLEAR_TOP，同时当前的 Task 里已经有了这个 Activity，那么情形又将不一样。
 * Android 不但不会启动新的 Activity 实例，而且还会将 Task 里 该 Activity 之上的所有 Activity 一律结束
 * 掉，然后将 Intent 发给这个已存在的 Activity。Activity 收到 Intent 之后，可以在 onNewIntent() 里做下
 * 一步的处理，也可以自行结束然后重新创建自己。如果 Activity 在 AndroidMainifest.xml 里将启动模式设置
 * 成”multiple”，– 默认模式，并且 Intent 里也没有设置 FLAG_ACTIVITY_SINGLE_TOP，那么它将选择后者。否
 * 则，它将选择前者。FLAG_ACTIVITY_CLEAR_TOP 还可以和 FLAG_ACTION_NEW_TASK 配合使用。
 * 
 * 如果 flag 设置的是 FLAG_ACTIVITY_SINGLE_TOP，则意味着如果 Activity 已经是运行在 Task 的 top，则该
 *  Activity 将不会再被启动。
 *  
 * 
 * 设置intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
 * 
 * 下面是关于setFlags的一下属性的解释：
 * 
 * 一、Activity和Task(栈)的关系
 * Task就像一个容器，而Activity就相当与填充这个容器的东西，第一个东西（Activity）则会处于最下面，最后
 * 添加的东西（Activity）则会在最低端。从Task中取出东西（Activity）则是从最顶端取出，也就是说最先取出
 * 的是最后添加的东西（Activity），一次类推，最后取出的是第一次添加的Activity，而Activity在Task中的顺
 * 序是可以控制的，那则在Activity跳转时用到Intent Flag
 * 
 * 二、界面跳转和服务的启动都会用到Intent，现在介绍Intent Flag是关于Activity的跳转
 * Intent intent = new Intent(this,xxx.class);
 * //如果activity在task存在，拿到最顶端,不会启动新的Activity
 * intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
 * //如果activity在task存在，将Activity之上的所有Activity结束掉
 * intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 * //默认的跳转类型,将Activity放到一个新的Task中
 * intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 * //如果Activity已经运行到了Task，再次跳转不会在运行这个Activity
 * intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
 * 来自：http://www.anddevs.com/?p=118
 * 
 * 
 * 1.Activity的affinity(亲和力)
 * 2.Intent几种常见的flags
 * 3.<activity>与task相关属性
 * 
 * affinity：
 * 
 * task对于Activity来说就好像它的身份证一样，可以告诉所在的task，自己属于这个task中的一员；拥有相同affinity
 * 的多个Activity理论同属于一个task，task自身的affinity决定于根Activity的affinity值。affinity在什么场合应
 * 用呢？
 * 
 * 1.根据affinity重新为Activity选择宿主task（与allowTaskReparenting属性配合工作）；
 * 
 * 2.启动一个Activity过程中Intent使用了FLAG_ACTIVITY_NEW_TASK标记，根据affinity查找或创建一个新的具有对应
 * affinity的task。我们会在后面进行详细讲解。
 * 默认情况下，一个应用内的所有Activity都具有相同的affinity，都是从Application（参考<application>的taskAffinity
 * 属性）继承而来，而Application默认的affinity是<manifest>中的包名，我们可以为<application>设置taskAffinity
 * 属性值，这样可以应用到<application>下的所有<activity>，也可以单独为某个Activity设置taskAffinity。
 * 例如：在系统自带的Browser中，package为com.android.browser，但是<application>却自定义一个taskAffinity属性值：
 *  
 * <application   android:name="Browser"  
 *                android:label="@string/application_name"  
 *                android:icon="@drawable/ic_launcher_browser"  
 *                android:backupAgent=".BrowserBackupAgent"  
 *                android:taskAffinity="android.task.browser" >
 *                
 * Intent几种常见的flags：
 * 在android.content.Intent中定义了若干个flags，其中最重要的有以下几个：
 * 1.FLAG_ACTIVITY_NEW_TASK：当Intent对象包含这个标记时，系统会寻找或创建一个新的task来放置目标Activity，寻找时
 * 依据目标Activity的taskAffinity属性进行匹配，如果找到一个task的taskAffinity与之相同，就将目标Activity压入此
 * task中，如果查找无果，则创建一个新的task，并将该task的taskAffinity设置为目标Activity的taskActivity，将目标
 * Activity放置于此task。注意，如果同一个应用中Activity的taskAffinity都使用默认值或都设置相同值时，应用内的
 * Activity之间的跳转使用这个标记是没有意义的，因为当前应用task就是目标Activity最好的宿主。
 * </pre>
 * 
 * @see http://blog.csdn.net/liuhe688/article/details/6761337
 * @author Sansan
 * 
 */
public class FirstActivity extends Activity implements OnClickListener, OnCheckedChangeListener {

	private final String TAG = this.getClass().getSimpleName();
	// List<CheckBox> checkboxList = new ArrayList<CheckBox>();
	private int flags;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_intent);

		TextView tvTaskId = (TextView) findViewById(R.id.tvTaskId);
		tvTaskId.setText(getCallingActivity() + "\n\n" + getClass().getSimpleName() + " : TaskId = " + getTaskId()
				+ "\nisTaskRoot() = " + isTaskRoot());

		// Title_HashCode_[R]TaskId
		setTitle(getTitle() + "_" + Integer.toHexString(System.identityHashCode(this)) + "_" + (isTaskRoot() ? "R" : "")
				+ getTaskId());

		findViewById(R.id.startFirstActivity).setOnClickListener(this);
		findViewById(R.id.startSecondActivity).setOnClickListener(this);

		// 如果activity在task存在，拿到最顶端,不会启动新的Activity
		handleCheckBox(R.id.chk_brought_to_front, Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);

		// 默认的跳转类型,将Activity放到一个新的Task中
		handleCheckBox(R.id.chk_newtask, Intent.FLAG_ACTIVITY_NEW_TASK);

		// >>>>>>>如果activity在task存在，将Activity之上的所有Activity结束掉
		handleCheckBox(R.id.chk_cleartop, Intent.FLAG_ACTIVITY_CLEAR_TOP);

		handleCheckBox(R.id.chk_resettaskifneeded, Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

		// 如果Activity已经运行到了Task，再次跳转不会在运行这个Activity
		handleCheckBox(R.id.chk_singletop, Intent.FLAG_ACTIVITY_SINGLE_TOP);

	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub

		super.onDestroy();
	}

	private void handleCheckBox(int id, int flag) {
		CheckBox checkBox = (CheckBox) findViewById(id);
		checkBox.setOnCheckedChangeListener(this);
		// checkboxList.add(checkBox);
		checkBox.setId(flag);
	}

	@Override
	public void onBackPressed() {
		if (null == getCallingActivity()) {
			Toast.makeText(this, "getCallingActivity is null.", Toast.LENGTH_SHORT).show();
		}
		// 数据是使用Intent返回
		Intent intent = new Intent();
		// 把返回数据存入Intent
		intent.putExtra("result", "My result " + getClass().getSimpleName());
		// 设置返回数据
		this.setResult(RESULT_OK, intent);
		// 关闭Activity
		this.finish();
		super.onBackPressed();
	}

	/**
	 * 为了得到传回的数据，必须在前面的Activity中（指MainActivity类）重写onActivityResult方法
	 * 
	 * requestCode 请求码，即调用startActivityForResult()传递过去的值 resultCode 结果码，结果码用于标识返回数据来自哪个新Activity
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		String result = data.getExtras().getString("result");// 得到新Activity 关闭后返回的数据
		Log.i(TAG, result);
	}

	@Override
	public void onClick(View v) {
		Class<?> clz = v.getId() == R.id.startFirstActivity ? FirstActivity.class : SecondActivity.class;
		Intent intent = new Intent(this, clz);
		// 得到新打开Activity关闭后返回的数据
		// 第二个参数为请求码，可以根据业务需求自己编号
		startActivityForResult(intent, 0);

		// startOtherAppByBroadcast();
	}

	/**
	 * In another app
	 * <pre>
	 * 	private BroadcastReceiver dynamicReceiver;
	 * 
	 * 		dynamicReceiver = new BroadcastReceiver() {
	 * 			@Override
	 * 			public void onReceive(Context context, Intent intent) {
	 * 				// TODO Auto-generated method stub
	 * 				Intent startActIntent = new Intent(MainActivity.this, MainActivity.class);
	 * 				//startActIntent.setClassName(intent.getStringExtra("packageContext"), intent.getStringExtra("className"));
	 * 				int flags = intent.getIntExtra("flags", Intent.FLAG_ACTIVITY_NEW_TASK);
	 * 				startActIntent.setFlags(flags);
	 * 				Toast.makeText(getApplicationContext(), "startActivity flags = " + flags, Toast.LENGTH_LONG).show();
	 * 				startActivity(startActIntent);
	 * 			}
	 * 		};
	 * 		IntentFilter filter = new IntentFilter();
	 * 		filter.addAction("android.app.Activity.startActivity");
	 * 		registerReceiver(dynamicReceiver, filter);
	 * 
	 * 	@Override
	 * 	protected void onDestroy() {
	 * 		// TODO Auto-generated method stub
	 * 		unregisterReceiver(dynamicReceiver);
	 * 		super.onDestroy();
	 * 	}
	 * </pre>
	 */
	private void startOtherAppByBroadcast() {
		Intent intent = new Intent();
		// intent.setClassName("com.a.b", "com.a.b.MainActivity");
		intent.putExtra("flags", flags);
		intent.putExtra("packageContext", "com.a.b");
		intent.putExtra("className", "com.a.b.MainActivity");
		intent.setAction("android.app.Activity.startActivity");
		sendBroadcast(intent);
	}

	@Override
	public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
		if (isChecked)
			flags |= buttonView.getId();
		else
			flags &= ~buttonView.getId();
	}
}
